﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Data.Models;

using Data.Models.Enums;
using Harmonogramowanie;

namespace Braincase.GanttChart
{
    /// <summary>
    /// An elaborate example on how the chart control might be used. 
    /// Start by collapsing all regions and then read the constructor.
    /// Refer to IProjectManager interface for method description.
    /// </summary>
    public partial class GanttForm : Form
    {
        OverlayPainter _mOverlay = new OverlayPainter();
        ProjectManager _mManager = null;
        CGraph G = new CGraph();

        /// <summary>
        /// Example starts here
        /// </summary>
        public GanttForm(int projectInd)
        {
            InitializeComponent();

            var db = new ProjectScheduleContext();
            var project = db.Projects.First(x => x.Id == projectInd);

            List<Operation> operations = db.Operations.Where(x => x.Project.Id == project.Id).ToList();

            //inicjalizacja grafu
            G.Init(operations.Count);

            var taskDictionary = new Dictionary<int, MyTask>();
            var operationDictionary = new Dictionary<int, Operation>();
            var resourceDictionary = new Dictionary<int, Resource>();


            var query = from b in db.Operations
                        where b.Project.Id == projectInd
                        orderby b.Id
                        select b.Resource.Id;/* new Project_Schedule.Models.Operation
                        {
                            Id = b.Id,
                            Kolejność = b.Order,
                            Nazwa = b.Name,
                            Czas = b.Duration,
                            Następniki = b.NextOperation,
                            Opis = b.Description,
                            Zasób = b.Resource.Id,
                            Projekt = b.Project.Id

                        };*/

            var lista = query.ToList();

            foreach (var item in lista)
            {
                if (!resourceDictionary.ContainsKey(item))
                    resourceDictionary.Add(item, db.Resources.First(x => x.Id == item));
            }

            _mManager = new ProjectManager();

            foreach (var task in operations)
            {
                taskDictionary.Add(task.Id, new MyTask(_mManager) { Nazwa = task.Name, TaskIdentyfier = (int)task.Order });
                operationDictionary.Add(task.Id, task);
            }



            //kolejność topologiczna
            foreach (var task in taskDictionary)
            {
                foreach (var item in operationDictionary[task.Key].NextOperation.Trim().Split(';'))
                    if (!string.IsNullOrWhiteSpace(item))
                    {
                        G.addarc(taskDictionary[task.Key].TaskIdentyfier, taskDictionary[int.Parse(item)].TaskIdentyfier);
                    }
            }

            int[] listaTopologiczna = ScheduleCore.TopOrder(G);
            var słownikTopologiczny = new Dictionary<int, MyTask>();

            foreach (var item in listaTopologiczna)
            {
                if (item == 0)
                    continue;
                var oper = operations.First(x => x.Order == item);
                słownikTopologiczny.Add(oper.Id, new MyTask(_mManager) { Nazwa = oper.Name });
            }

            taskDictionary = słownikTopologiczny;

            // Create a Project and some Tasks
            foreach (var task in taskDictionary)
            {
                _mManager.Add(task.Value);
            }




            // Set task durations, e.g. using ProjectManager methods 

            foreach (var task in taskDictionary)
            {
                _mManager.SetDuration(task.Value, operationDictionary[task.Key].Duration);
            }

            // demostrate splitting a task
            // _mManager.Split(pack, new MyTask(_mManager), new MyTask(_mManager), 2);

            // Set task complete status, e.g. using newly created properties
            //  wake.Complete = 0.9f;
            //  teeth.Complete = 0.5f;
            //  shower.Complete = 0.4f;

            // Give the Tasks some organisation, setting group and precedents

            Task finalTask = new Task() { Nazwa = project.Name };
            _mManager.Add(finalTask);

            foreach (var task in taskDictionary)
            {
                _mManager.Group(finalTask, task.Value);

            }


            foreach (var task in taskDictionary)
            {
                foreach (var item in operationDictionary[task.Key].NextOperation.Trim().Split(';'))
                    if (!string.IsNullOrWhiteSpace(item))
                    {
                        _mManager.Relate(taskDictionary[task.Key], taskDictionary[int.Parse(item)]);
                    }
            }

            // Create and assign Resources.
            // MyResource is just custom user class. The API can accept any object as resource.

            foreach (var item in operations)
            {
                //if(resourceDictionary.ContainsKey(item.Resource.Id))
                _mManager.Assign(taskDictionary[item.Id], new MyResource() { Name = resourceDictionary[item.Resource.Id].Name });
            }



            // Initialize the Chart with our ProjectManager and CreateTaskDelegate
            _mChart.Init(_mManager);
            _mChart.CreateTaskDelegate = () => new MyTask(_mManager);

            // Attach event listeners for events we are interested in
            _mChart.TaskMouseOver += new EventHandler<TaskMouseEventArgs>(_mChart_TaskMouseOver);
            _mChart.TaskMouseOut += new EventHandler<TaskMouseEventArgs>(_mChart_TaskMouseOut);
            _mChart.TaskSelected += new EventHandler<TaskMouseEventArgs>(_mChart_TaskSelected);
            _mChart.PaintOverlay += _mOverlay.ChartOverlayPainter;
            _mChart.AllowTaskDragDrop = true;

            // set some tooltips to show the resources in each task
            //  _mChart.SetToolTip(wake, string.Join(", ", _mManager.ResourcesOf(wake).Select(x => (x as MyResource).Name)));
            //_mChart.SetToolTip(teeth, string.Join(", ", _mManager.ResourcesOf(teeth).Select(x => (x as MyResource).Name)));
            // _mChart.SetToolTip(pack, string.Join(", ", _mManager.ResourcesOf(pack).Select(x => (x as MyResource).Name)));
            //_mChart.SetToolTip(shower, string.Join(", ", _mManager.ResourcesOf(shower).Select(x => (x as MyResource).Name)));

            // Set Time information
            _mManager.TimeScale = TimeScale.Day;
            var span = DateTime.Today - _mManager.Start;
            _mManager.Now = (int)Math.Round(span.TotalDays); // set the "Now" marker at the correct date
            _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfWeek; // Set the chart to display days of week in header

            // Init the rest of the UI
            _InitExampleUI();
        }

        void _mChart_TaskSelected(object sender, TaskMouseEventArgs e)
        {
            _mTaskGrid.SelectedObjects = _mChart.SelectedTasks.Select(x => _mManager.IsPart(x) ? _mManager.SplitTaskOf(x) : x).ToArray();
            _mResourceGrid.Items.Clear();
            _mResourceGrid.Items.AddRange(_mManager.ResourcesOf(e.Task).Select(x => new ListViewItem(((MyResource)x).Name)).ToArray());
        }

        void _mChart_TaskMouseOut(object sender, TaskMouseEventArgs e)
        {
            lblStatus.Text = "";
            _mChart.Invalidate();
        }

        void _mChart_TaskMouseOver(object sender, TaskMouseEventArgs e)
        {
            lblStatus.Text = string.Format("{0} to {1}", _mManager.GetDateTime(e.Task.Start).ToLongDateString(), _mManager.GetDateTime(e.Task.Koniec).ToLongDateString());
            _mChart.Invalidate();
        }

        private void _InitExampleUI()
        {
            TaskGridView.DataSource = new BindingSource(_mManager.Tasks, null);
            mnuFilePrint200.Click += (s, e) => _Print(2.0f);
            mnuFilePrint150.Click += (s, e) => _Print(1.5f);
            mnuFilePrint100.Click += (s, e) => _Print(1.0f);
            mnuFilePrint80.Click += (s, e) => _Print(0.8f);
            mnuFilePrint50.Click += (s, e) => _Print(0.5f);
            mnuFilePrint25.Click += (s, e) => _Print(0.25f);
            mnuFilePrint10.Click += (s, e) => _Print(0.1f);
        }

        #region Main Menu

        private void mnuFileSave_Click(object sender, EventArgs e)
        {
            using (var dialog = new SaveFileDialog())
            {
                dialog.InitialDirectory = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    using (var fs = System.IO.File.OpenWrite(dialog.FileName))
                    {
                        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                        bf.Serialize(fs, _mManager);
                    }
                }
            }
        }

        private void mnuFileOpen_Click(object sender, EventArgs e)
        {
            using (var dialog = new OpenFileDialog())
            {
                dialog.InitialDirectory = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    using (var fs = System.IO.File.OpenRead(dialog.FileName))
                    {
                        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                        _mManager = bf.Deserialize(fs) as ProjectManager;
                        if (_mManager == null)
                        {
                            MessageBox.Show("Unable to load ProjectManager. Data structure might have changed from previous verions", "Gantt Chart", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                        else
                        {
                            _mChart.Init(_mManager);
                            _mChart.Invalidate();
                        }
                    }
                }
            }
        }

        private void mnuFileExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void mnuViewDaysDayOfWeek_Click(object sender, EventArgs e)
        {
            _mManager.TimeScale = TimeScale.Day;
            _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfWeek;
            _mChart.Invalidate();
        }

        private void mnuFileNew_Click(object sender, EventArgs e)
        {
            // start a new Project and init the chart with the project
            _mManager = new ProjectManager();
            _mManager.Add(new Task() { Nazwa = "New Task" });
            _mChart.Init(_mManager);
            _mChart.Invalidate();
        }

        private void mnuHelpAbout_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Program prezentujący projek z podziłaem na zadania ", "Drabiniok Malek - Gantt Chart", MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.OK)
            {
                System.Diagnostics.Process.Start("http://rodion.no-ip.biz/");
            }
        }


        private void mnuViewRelationships_Click(object sender, EventArgs e)
        {
            _mChart.ShowRelations = mnuViewRelationships.Checked = !mnuViewRelationships.Checked;
            _mChart.Invalidate();
        }

        private void mnuViewSlack_Click(object sender, EventArgs e)
        {
            _mChart.ShowSlack = mnuViewSlack.Checked = !mnuViewSlack.Checked;
            _mChart.Invalidate();
        }

        private void mnuViewIntructions_Click(object sender, EventArgs e)
        {
            _mOverlay.PrintMode = !(mnuViewIntructions.Checked = !mnuViewIntructions.Checked);
            _mChart.Invalidate();
        }

        #region Timescale Views
        private void mnuViewDays_Click(object sender, EventArgs e)
        {
            _mManager.TimeScale = TimeScale.Day;
            mnuViewDays.Checked = true;
            mnuViewWeek.Checked = false;
            _mChart.Invalidate();
        }

        private void mnuViewWeek_Click(object sender, EventArgs e)
        {
            _mManager.TimeScale = TimeScale.Week;
            mnuViewDays.Checked = false;
            mnuViewWeek.Checked = true;
            _mChart.Invalidate();
        }

        private void mnuViewDayOfWeek_Click(object sender, EventArgs e)
        {
            _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfWeek;
            mnuViewDayOfWeek.Checked = true;
            mnuViewDayOfMonth.Checked = false;
            mnuViewWeekOfYear.Checked = false;
            _mChart.Invalidate();
        }

        private void mnuViewDayOfMonth_Click(object sender, EventArgs e)
        {
            _mChart.TimeScaleDisplay = TimeScaleDisplay.DayOfMonth;
            mnuViewDayOfWeek.Checked = false;
            mnuViewDayOfMonth.Checked = true;
            mnuViewWeekOfYear.Checked = false;
            _mChart.Invalidate();
        }

        private void mnuViewWeekOfYear_Click(object sender, EventArgs e)
        {
            _mChart.TimeScaleDisplay = TimeScaleDisplay.WeekOfYear;
            mnuViewDayOfWeek.Checked = false;
            mnuViewDayOfMonth.Checked = false;
            mnuViewWeekOfYear.Checked = true;
            _mChart.Invalidate();
        }
        #endregion Timescale Views

        #endregion Main Menu

        #region Sidebar

        private void _mDateTimePicker_ValueChanged(object sender, EventArgs e)
        {
            _mManager.Start = _mStartDatePicker.Value;
            var span = DateTime.Today - _mManager.Start;
            _mManager.Now = (int)Math.Round(span.TotalDays);
            if (_mManager.TimeScale == TimeScale.Week) _mManager.Now = (_mManager.Now % 7) * 7;
            _mChart.Invalidate();
        }

        private void _mPropertyGrid_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
        {
            _mChart.Invalidate();
        }

        private void _mNowDatePicker_ValueChanged(object sender, EventArgs e)
        {
            TimeSpan span = _mNowDatePicker.Value - _mStartDatePicker.Value;
            _mManager.Now = span.Days + 1;
            if (_mManager.TimeScale == TimeScale.Week) _mManager.Now = _mManager.Now / 7 + (_mManager.Now % 7 > 0 ? 1 : 0);
            _mChart.Invalidate();
        }

        private void _mScrollDatePicker_ValueChanged(object sender, EventArgs e)
        {
            _mChart.ScrollTo(_mScrollDatePicker.Value);
            _mChart.Invalidate();
        }

        private void _mTaskGridView_SelectionChanged(object sender, EventArgs e)
        {
            if (TaskGridView.SelectedRows.Count > 0)
            {
                var task = TaskGridView.SelectedRows[0].DataBoundItem as Task;
                _mChart.ScrollTo(task);
            }
        }

        #endregion Sidebar

        #region Print

        private void _Print(float scale)
        {
            using (var dialog = new PrintDialog())
            {
                dialog.Document = new System.Drawing.Printing.PrintDocument();
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    // set the print mode for the custom overlay painter so that we skip printing instructions
                    dialog.Document.BeginPrint += (s, arg) => _mOverlay.PrintMode = true;
                    dialog.Document.EndPrint += (s, arg) => _mOverlay.PrintMode = false;

                    // tell chart to print to the document at the specified scale
                    _mChart.Print(dialog.Document, scale);
                }
            }
        }

        #endregion Print
    }

    #region overlay painter
    /// <summary>
    /// An example of how to encapsulate a helper painter for painter additional features on Chart
    /// </summary>
    public class OverlayPainter
    {
        /// <summary>
        /// Hook such a method to the chart paint event listeners
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ChartOverlayPainter(object sender, ChartPaintEventArgs e)
        {/*
            // Don't want to print instructions to file
            if (this.PrintMode) return;

            var g = e.Graphics;
            var chart = e.Chart;

            // Demo: Static billboards begin -----------------------------------
            // Demonstrate how to draw static billboards
            // "push matrix" -- save our transformation matrix
            e.Chart.BeginBillboardMode(e.Graphics);

            // draw mouse command instructions
            int margin = 300;
            int left = 20;
            var color = chart.HeaderFormat.Color;
            StringBuilder builder = new StringBuilder();
            builder.AppendLine("THIS IS DRAWN BY A CUSTOM OVERLAY PAINTER TO SHOW DEFAULT MOUSE COMMANDS.");
            builder.AppendLine("*******************************************************************************************************");
            builder.AppendLine("Left Click - Select task and display properties in PropertyGrid");
            builder.AppendLine("Left Mouse Drag - Change task starting point");
            builder.AppendLine("Right Mouse Drag - Change task duration");
            builder.AppendLine("Middle Mouse Drag - Change task complete percentage");
            builder.AppendLine("Left Doubleclick - Toggle collaspe on task group");
            builder.AppendLine("Right Doubleclick - Split task into task parts");
            builder.AppendLine("Left Mouse Dragdrop onto another task - Group drag task under drop task");
            builder.AppendLine("Right Mouse Dragdrop onto another task part - Join task parts");
            builder.AppendLine("SHIFT + Left Mouse Dragdrop onto another task - Make drop task precedent of drag task");
            builder.AppendLine("ALT + Left Dragdrop onto another task - Ungroup drag task from drop task / Remove drop task from drag task precedent list");
            builder.AppendLine("SHIFT + Left Mouse Dragdrop - Order tasks");
            builder.AppendLine("SHIFT + Middle Click - Create new task");
            builder.AppendLine("ALT + Middle Click - Delete task");
            builder.AppendLine("Left Doubleclick - Toggle collaspe on task group");
            var size = g.MeasureString(builder.ToString(), e.Chart.Font);
            var background = new Rectangle(left, chart.Height - margin, (int)size.Width, (int)size.Height);
            background.Inflate(10, 10);
            g.FillRectangle(new System.Drawing.Drawing2D.LinearGradientBrush(background, Color.LightYellow, Color.Transparent, System.Drawing.Drawing2D.LinearGradientMode.Vertical), background);
            g.DrawRectangle(Pens.Brown, background);
            g.DrawString(builder.ToString(), chart.Font, color, new PointF(left, chart.Height - margin));


            // "pop matrix" -- restore the previous matrix
            e.Chart.EndBillboardMode(e.Graphics);
            // Demo: Static billboards end -----------------------------------*/
        }

        public bool PrintMode { get; set; }
    }
    #endregion overlay painter

    #region custom task and resource
    /// <summary>
    /// A custom resource of your own type (optional)
    /// </summary>
    [Serializable]
    public class MyResource
    {
        public string Name { get; set; }
    }
    /// <summary>
    /// A custom task of your own type deriving from the Task interface (optional)
    /// </summary>
    [Serializable]
    public class MyTask : Task
    {
        public MyTask(ProjectManager manager)
            : base()
        {
            Manager = manager;
        }

        private ProjectManager Manager { get; set; }
        public int TaskIdentyfier { get; set; }

        public new int Start { get { return base.Start; } set { Manager.SetStart(this, value); } }
        public new int Koniec { get { return base.Koniec; } set { Manager.SetEnd(this, value); } }
        public new int Czas_Trwania { get { return base.Czas_Trwania; } set { Manager.SetDuration(this, value); } }
        public new float Zaawansowanie { get { return base.Zaawansowanie; } set { Manager.SetComplete(this, value); } }
    }
    #endregion custom task and resource
}